
package horde.utils;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;


/**
 * @author Andres Picazo Cuesta
 */
public class SynchronizedQueue<T> {

    private Queue queue;

    public SynchronizedQueue () {
        queue = new LinkedList<T>();
    }

    /**
     * Retrieves the next element from the queue and removes the element from it
     * @return The polled element
     * @throws InterruptedException
     */
    public synchronized T poll () throws InterruptedException {
        while (queue.size() == 0) wait();
        T element = (T) queue.poll();
        notifyAll();
        return element;
    }

    /**
     * Inserts the element into the queue
     * @param element The element to insert
     * @throws InterruptedException
     */
    public synchronized boolean offer (T element) throws InterruptedException {
        boolean result = queue.offer(element);
        notifyAll();
        return result;
    }

    /**
     * Add the element to the head of the queue instead of the tail
     * @param element The element to insert
     * @throws InterruptedException
     */
    public synchronized void offerFirst (T element) throws InterruptedException {
        ((LinkedList)queue).addFirst(element);
        notifyAll();
    }

    public T peek () {
        return (T) queue.peek();
    }

    public void test () {
        SynchronizedQueue<String>queue = new SynchronizedQueue<String>();
        Scanner sc = new  Scanner(System.in);
        String readed = "";
        int delayBetweenConsumptions;
        Runnable consumer = new Consumer(queue, delayBetweenConsumptions = 2000);
        Thread consumerThread = new Thread(consumer);
        consumerThread.start();
        while (!readed.equals("exit")) {
            try {
                System.out.println ("type next element (exit to finish)");
                readed = sc.nextLine();
                queue.offer(readed);
            }
            catch (Exception e) {
                System.err.println ("An exception has been thrown!!");
            }
        }
    }

    /* Only for testing purposes */
    private static class Consumer implements Runnable {
        SynchronizedQueue queue;
        boolean stop = false;
        int delay;
        public Consumer (SynchronizedQueue queue, int delayBetweenConsumptions) {
            this.queue = queue;
            delay = delayBetweenConsumptions;
        }

        public void run() {
            System.err.println ("consumer started!");
            while (!stop) {
                try {
                    String s = queue.poll().toString();
                    Thread.sleep(delay);
                    System.err.println ("Consuming: " + s);
                    if (s.equals("exit")) stop = true;
                }
                catch (Exception e) {
                    System.err.println("Unable to poll element (Exception)");
                }
            }
            System.err.println ("Stopping consumer");
        }        
    }

}
